package tde_servicer

import (
	"bufio"
	"fmt"
	"ifms/db_svr"
	"net"
	"regexp"
	"strconv"
	"time"
)

func Write(w *bufio.Writer, data string) string {
	// we may never have data less than 5 byte
	if len(data) < 5 {
		return "F"
	}

	if _, err := w.WriteString(data + "\n"); err != nil {
		logger.Printf(" Write [%v] error:%s\n", data, err)

		return "F"
	}
	if err := w.Flush(); err != nil {
		logger.Printf(" Flush [%v] error: %s\n", data, err)
		return "F"
	}

	return "S"

}

func Tde_session(conn net.Conn) {
	defer conn.Close()
	remoteHost := conn.RemoteAddr().String()
	ip, p, err := net.SplitHostPort(remoteHost)

	if err != nil {
		logger.Println(err)
	}
	if !regexp.MustCompile(`^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$`).MatchString(ip) {
		ip = "localhost"
	}
	port, err := strconv.Atoi(p)
	if err != nil {
		port = 0
	}

	logger.Printf("Session connected from : %v:%v.\n", ip, port)

	reader := bufio.NewReader(conn)
	writer := bufio.NewWriter(conn)
	incoming := make(chan string)
	outgoing := make(chan string, 5)

	quit := make(chan bool)
	var loginFlag bool = false
	var user_id int32
	var userName string
	var msg []string
	var message string

	go func() {

	RL:
		for {
			select {
			case <-quit:
				break RL

			default:
				if line, err := reader.ReadString('\n'); err == nil {
					incoming <- string(line)
				} else {
					logger.Printf("Session[ user: %v] Read error: %s\n", userName, err)

					break RL
				}

			}

		}
		logger.Printf("Session Read exited...\n")
		quit <- true

	}()

	go func() {

	L:
		for {
			select {
			case <-quit:

				break L

			case s := <-outgoing:
				if Write(writer, s) == "F" {
					break L
				}

			}

		}
		logger.Printf("Connection [user:%v] Write Error, will be dis-connected soon.\n", userName)
		quit <- true

	}()

	time.Sleep(1 * time.Microsecond)

	timeOut := time.NewTimer(30 * time.Second).C

L:
	for i := 1; i < maxLoginFailRestriction && !loginFlag; i++ {

		select {
		case <-quit:
			break L
		case <-timeOut:

			logger.Printf("Login timeout, dis-connecting...\n")
			outgoing <- `{"flag":-1,"interface":"AP", "message":"Login timeout, dis-connecting... "}`
			break L
		case message = <-incoming:

			msg = regexp.MustCompile(";").Split(message, -1)
			logger.Printf(" incoming: %v => %v \n", message, msg)

			if msg[0] != "#" || msg[4] != "$" || (msg[2] != "VD" && msg[2] != "VV") {
				outgoing <- fmt.Sprintf(`{"flag":"-1","interface":"%v","message":"Authorize Failed, count:%d"}`, msg[2], i)
				logger.Printf("Authorize Failed %v times, wrong format, client says:%v\n", i, msg)
				continue
			}
		}

		d := regexp.MustCompile(",").Split(msg[3], -1)

		// uname, verifyMode, pass, ip, valid_dt, exp_dt string, port int32)
		logger.Printf("Client data fields: %v\n", d)

		duration, dbmsg := db_svr.UserAuth(msg[1], //unmae
			msg[2],      //vreifyMode, 'VV' or 'VD'
			d[0],        //p_pass
			ip,          //p_ip_addr
			d[1],        //p_pass_valid_dt
			d[2],        //p_pass_exp_dt
			int32(port)) //p_port

		outgoing <- dbmsg.Data

		logger.Printf("duration:%v", duration)

		if dbmsg.Flag == 0 {
			loginFlag = true
			user_id = int32(dbmsg.User_id)
			userName = msg[1]
			timeOut = time.NewTimer(time.Duration(duration) * time.Second).C
			logger.Printf("Seesion [User:%v] Login suceed.\n", userName)

			break
		} else {
			logger.Printf("Session [User:%v] Loin failer %v times: %v\n", userName, i, dbmsg.Message)
		}

	}
	if !loginFlag {
		logger.Printf("Session [User:%v] Login Failed", userName)
		quit <- true
	}

	go func() { // hub for coming data
		var retmsg string
		//	logger.Printf("Session User [%v] Start to process incoming msg.... \n", userName)
	HL:
		for {
			select {
			case <-quit:
				quit <- true
				break HL
			case <-timeOut:
				logger.Printf("User [%v] Current verification Expired, will logout.", userName)
				outgoing <- `{"flag":1,"interface":"AP","message":"Current Verfification Expired!"}`
				break HL

			case s := <-incoming:
				msg = regexp.MustCompile(";").Split(s, -1)

				logger.Printf("User %v[%v] says: %v", userName, user_id, msg)
				if len(msg) != 6 || msg[0] != "#" || msg[4] != "$" {
					retmsg = "Incoming msg format error, ignored."
					logger.Printf("%v\n", retmsg)
					outgoing <- fmt.Sprintf(`{"flag":-1,"interface":"%v","message":"%v"}`, msg[2], retmsg)
					break

				}

				d := regexp.MustCompile(",").Split(msg[3], -1)

				logger.Printf("msg[3]:%v\n", d)
				switch msg[2] {
				case "DV": //Verfication Code Disable

					duration, dbmsg := db_svr.UserAuth(msg[1], //unmae
						msg[2],      //vreifyMode, 'VV' or 'VD'
						d[0],        //p_pass
						ip,          //p_ip_addr
						d[1],        //p_pass_valid_dt
						d[2],        //p_pass_exp_dt
						int32(port)) //p_port

					outgoing <- dbmsg.Data
					timeOut = time.NewTicker(time.Duration(duration) * time.Second).C

					logger.Printf("Disabled Current Verification Code for User:%v.\n", userName)

				case "DS": // Data Sync
					if len(d[0]) != 15 {
						retmsg = "Device ID must 15 char in length, please check."

						logger.Printf("User[%v] Incoming ignored. Reason : %v\n", userName, retmsg)

						// outgoing <- fmt.Sprintf(`{"flag":-1,"interface":"%v","message":"%v"}`, msg[2], retmsg)
						// ??????????????????? better solution ???????????????????????
						break

					} else {

						db_svr.DataSync(d[0], "", "", outgoing)
					}

				case "TD": // Time Window Data Re-Sync

					if len(d[0]) != 15 {
						retmsg = "Device ID must 15 char in length, please check"

						logger.Printf("User [%v] Incoming ignored. Reason : %v\n", userName, retmsg)
						//outgoing <- fmt.Sprintf(`{"flag":-1,"interface":"%v","message":"%v : [%v]"}`, msg[2], retmsg, d[0])
						break

					}

					if !validDateTimeFormat(d[1]) || !validDateTimeFormat(d[2]) {

						retmsg = "Invalid Date format in start_dt and/or end_dt, please check"

						logger.Printf("User [%v] Incoming ignored. Reason : %v , '%v', '%v' \n", userName, retmsg, d[1], d[2])
						//outgoing <- fmt.Sprintf(`{"flag":-1,"interface":"%v","message":"%v: '%v','%v'"}`, msg[2],retmsg, d[1], d[2])
						break

					}

					db_svr.DataSync(d[0], d[1], d[2], outgoing)

				case "MR":
					if len(d) != 6 {
						retmsg = "Interface MR requests 6 uploading parameters, please check."

						logger.Printf("User [%v] Incoming ignored. Reason : %v\n", userName, retmsg)
						outgoing <- fmt.Sprintf(`{"flag":-1,"interface":"%v","message":"%v"}`, msg[2], retmsg)
						break
					}

					if margin, err := convertString2Float64(d[1:6]); len(err) > 10 { // {"flag":=-1 ...
						retmsg = "All parameters should be number, except the device_id, please check"

						logger.Printf("User [%v] Incoming ignored. Reason : %v :%v \n", userName, retmsg, d[1:6])
						outgoing <- fmt.Sprintf(`{"flag":-1,"interface":"%v","message":"%v:%v"}`, msg[2], retmsg, d)

					} else {
						db_svr.SetDeviceMargin(outgoing, user_id, d[0], msg[2], margin[0], margin[1], margin[2], margin[3], margin[4])
						//func SetDeviceMargin(o chan string, p_user_id int32, p_device_id string, p_oxy_min, p_ph_min, p_ph_max, p_ammonia_nitrogen, p_temperature_min float64) {

					}

				case "EN":

					if alertNum, err := convertString2Int64(d[0:2]); len(err) > 10 { // {"flag":=-1 ...
						retmsg = "Interface EN requests 2 11-digit cellphone number, please check"

						logger.Printf("User [%v] Incoming ignored. Reason : %v : %v\n", userName, retmsg, d)
						outgoing <- fmt.Sprintf(`{"flag":-1,"interface":"%v","message":"%v:%v"}`, msg[2], retmsg, d)

					} else {

						db_svr.ModifyUserAlertNum(outgoing, user_id, msg[2], alertNum[0], alertNum[1])
						//func SetDeviceMargin(o chan string, p_user_id int32, p_device_id string, p_oxy_min, p_ph_min, p_ph_max, p_ammonia_nitrogen, p_temperature_min float64) {

					}

				case "DA":
					//not support
					retmsg = "Sorry, Interface 'DA' is not supported yet now."
					logger.Printf("To User[%v]: %v\n", userName, retmsg)
					outgoing <- fmt.Sprintf(`{"flag":-1,"interface":"%v","message":"%v"}`, msg[2], retmsg)
				default:
					retmsg = "Wrong interface, please check data and format.n"
					logger.Printf("To User[%v]: %v\n", userName, retmsg)
					outgoing <- fmt.Sprintf(`{"flag":-1,"interface":"%v","message":"%v"}`, msg[2], retmsg)

				}

			}

		} /// for HL
		quit <- true
		//close(quit)
	}()

	<-quit
	logger.Printf("Session [User: %v] quit.\n", userName)
}
